using System;
using System.Linq;
using System.Windows;
using System.Xml.Linq;
using TicTacToe.UI;
using TicTacToe.Core;
using TicTacToe.Core.Persistance;

namespace TicTacToe.Net
{
    sealed class NetGame : TicTacToeGame
    {
        private readonly Connection _connection;

        public Player LocalPlayer { get; private set; }
        public Player RemotePlayer { get; private set; }

        public delegate void ChatMsgReceivedDlg(string message);
        public event ChatMsgReceivedDlg OnChatMessageReceived;

        public void Shutdown()
        {
            _connection.Shutdown();
        }

        public void SendChatMessage(string message)
        {
            var msg = new NetMessage("chat", new XElement("message", message));
            _connection.SendMessage(msg);
        }

        public NetGame(Player hostPlayer, Player clientPlayer, Connection connection)
            : base(hostPlayer, clientPlayer)
        {
            _connection = connection;
            _connection.OnDisconnected += Disconnected;
            _connection.OnGameTurnReceived += TurnReceived;
            _connection.OnChatMessageReceived += ChatMessageReceived;

            OnGameOver += NetGame_OnGameOver;
            OnTurn += NetGame_OnTurn;

            LocalPlayer = (_connection.IsHost) ? PlayerOne : PlayerTwo;
            RemotePlayer = (LocalPlayer == PlayerOne) ? PlayerTwo : PlayerOne;
        }

        void Disconnected(object sender, EventArgs e)
        {
            if (IsOver)
                return;

            Action a = () =>
                {
                    var gameWindow = App.Current.Windows.OfType<GameWindow>().Single();
                    gameWindow.IsEnabled = false;

                    Shutdown();

                    MessageBox.Show("Connection to " + RemotePlayer.Name + " lost.", "Connection Lost", MessageBoxButton.OK, MessageBoxImage.Error);

                    new StartWindow().Show();
                    gameWindow.Close();
                };
            App.Current.Dispatcher.Invoke(a, null);
        }

        void ChatMessageReceived(object sender, NetMessageEventArgs e)
        {
            if (OnChatMessageReceived != null)
                OnChatMessageReceived((string) e.Message.Content.Value);
        }

        void TurnReceived(object sender, NetMessageEventArgs e)
        {
            var turn = Serialization.DeserializeToTurn(e.Message.Content);
            MakeTurn(turn);
        }

        void NetGame_OnTurn(object sender, TurnEventArgs e)
        {
            if (e.Turn.Player != LocalPlayer) return;

            var msg = new NetMessage("turn", e.Turn.Serialize());
            _connection.SendMessage(msg);
        }

        void NetGame_OnGameOver(object sender, GameOverEventArgs e)
        {
            if (_connection.IsHost)
                Shutdown();
        }
    }
}